import logging
import os
from typing import Any, Dict

from langchain_core.tools import tool, ToolException

from tools.amap_tool import check_delivery_range
from tools.llm_tool import call_llm
from tools.pine_cone_tool import search_menu_items_with_id

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def load_prompt(tool_name: str) -> str:
    """
    根据传入的工具名字 返回对应工具要用到的提示词模版内容（结构化指令）
    :param tool_name: 输入工具的名字
    :return: 提示词内容
    """
    try:
        project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        load_dir = project_dir + "/prompt/" + f"{tool_name}.txt"

        with open(load_dir, "r", encoding="utf-8") as f:
            return f.read().strip()
    except Exception as e:
        logger.error(f"加载提示词模版文件出错 {e}")
        return "请根据用户的当前输入问题,回答问题,生成结果"

@tool
def general_inquiry(query:str,context:str=None)->str:
    """
        常规问询工具

        处理用户的一般性问题，包括但不限于：
        - 餐厅介绍和服务信息
        - 营业时间和联系方式
        - 优惠活动和会员服务
        - 其他非菜品相关的咨询

        Args:
            query: 用户的问询内容
            context: 可选的上下文信息，用于提供更精准的回复

        Returns:
            str: 针对用户问询的智能回复

        Raises:
            ToolException: 当处理查询时发生错误
    """
    try:
        # 1. 加载普通查询工具的提示词模版
        general_prompt = load_prompt("general_inquiry")
        # 2. 调用模型（对结果做一次优化 处理真正常规问的问题：模型回复常规查询）扩展（各种优化的记忆组件选择 ）
        # 从记忆组件中加载记忆组件中的对话 然后格式化处理 插入到context,作为模型回答本轮普通查询的上下文参考(用户体现更高) TODO
        full_query = f"用户当前的问题:{query}\n\n 上下文内容:{context}" if context else f"用户当前的问题:{query}"
        llm_response = call_llm(full_query,general_prompt)

        # 写入到记忆组件(对模型回复的结果在做清洗，洗涤当前业务用到的 越精炼且有参考意义越好) TODO

        # 3. 返回结果（工具的结果 最终结果）
        return llm_response
    except Exception as  e:
        raise ToolException(f"调用general_inquiry工具失败,原因:{e}")

@tool
def menu_inquiry(query:str)->Dict[str,Any]:
    """
       智能菜品咨询工具

       专门处理与菜品相关的所有查询，包括：
       - 菜品介绍和详细信息
       - 价格和营养信息
       - 菜品推荐和搭配建议
       - 过敏原和饮食限制相关问题
       - 菜品可用性和特色介绍

       该工具会自动通过语义搜索找到最相关的菜品信息，然后基于这些信息回答用户问题。

       Args:
           query: 用户关于菜品的具体问题

       Returns:
           Dict[str, Any]: 包含推荐建议和菜品ID的字典
           {
               "recommendation": "基于菜品信息的推荐建议",
               "menu_ids": ["菜品ID1", "菜品ID2"]
           }

       Raises:
           ToolException: 当处理菜品查询时发生错误
    """
    # 1.加载提示词模版
    menu_prompt = load_prompt("menu_inquiry")
    # 2. 调用模型
    # 2.1 根据输入的问题（格式后的问题） 检索向量数据库
    similar_result = search_menu_items_with_id(query)
    # 2.2 从向量数据库中获取检索到的菜品
    similar_items = similar_result['contents']
    menu_context = "\n".join([f"- {item}" for item in similar_items]).strip()
    # 2.3 提供检索到菜品信息的上下文  TODO :继续携带上记忆组件的上下文
    full_query = f"当前用户输入的问题:{query}\n\n 提供的上下文内容:\n {menu_context}\n\n 请结合以上提供的信息,生成菜品信息的推荐" if menu_context else f"当前用户输入的问题:{query},结合一般性菜谱信息生成菜品信息的推荐"
    # 2.4 调用
    llm_response = call_llm(full_query, menu_prompt)

    # 3.返回模型结果
    return {
        "recommendation": llm_response,
        "menu_ids": similar_result["ids"]  # 菜品Id 从模型中在利用正则表达式提取
    }

@tool
def delivery_check_tool(address: str, travel_mode: str) -> str:
    """
    配送范围检查工具

    检查指定地址是否在配送范围内，并提供距离信息。

    Args:
        address: 配送地址
        travel_mode: 距离计算方式 (1=步行距离, 2=骑行距离, 3=驾车距离)

    Returns:
        str: 配送检查结果的格式化信息

    Raises:
        ToolException: 当配送检查失败时
    """

    # 调用配送检查功能
    try:
        result = check_delivery_range(address, travel_mode)

        MODE_MAPPING = {
            "1": "步行距离",
            "2": "骑行距离",
            "3": "驾车距离",

        }

        if result["status"] == "success":
            status_text = "✅ 可以配送" if result["in_range"] else "❌ 超出配送范围"

            response = f"""
        配送信息查询结果：
        配送地址：{result['formatted_address']}
        配送距离：{result['distance']}公里 ({MODE_MAPPING[travel_mode]})
        配送状态：{status_text}
                    """.strip()

        else:
            response = f"❌ 配送查询失败：{result['message']}"

        return response
    except  Exception as e:
        raise ToolException(f"配送检查失败: {str(e)}")

if __name__ == '__main__':
    # 1. 测试加载提示模版内容
    # print("1.测试不同工具对应加载到的提示模版内容 ")
    # general_prompt = load_prompt("general_inquiry")
    #
    # print(f"加载到的提示词模版内容:\n{general_prompt}")
    # menu_prompt = load_prompt("menu_inquiry")
    #
    # print(f"加载到的提示词模版内容:\n{menu_prompt}")

    # 2.测试常规查询的工具调用
    # print("\n2.测试常规查询的工具调用")
    # # llm_response=general_inquiry("请问你们餐厅的营业时间是多少")
    # # llm_response=general_inquiry("请问你们餐厅的位置在哪里")
    # llm_response=general_inquiry("请问你们的微信是什么")
    # print(f"常规查询工具调用后的结果:{llm_response}")

    # 3.测试菜品相关查询的工具调用
    # print("\n3.测试菜品相关查询的工具调用")
    # # llm_response1 = menu_inquiry("请帮我点川菜系列的菜品")
    # # llm_response1 = menu_inquiry("请帮我点一份麻婆豆腐")
    # llm_response1 = menu_inquiry("我想吃上海菜")
    # print(f"测试菜品相关查询的工具调用:{llm_response1}")

    # # 测试配送检查工具
    print("\n3. 测试配送检查工具:")
    try:
        result3 = delivery_check_tool.invoke({"address": "武汉大学", "travel_mode": "2"})
        print(f"回复: {result3}")
    except Exception as e:
        print(f"错误: {e}")

    print("\n" + "=" * 60)
    print("测试完成")
    print("=" * 60)